#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
排班进度监控工具
提供倒计时和进度条显示功能，方便用户监控自动排班进度
"""

import sys
import time
import threading
import datetime
from typing import Optional, Callable, Dict, Any


class CountdownTimer:
    """倒计时计时器，显示距离下一次排班的剩余时间"""

    def __init__(self, minutes: int = 1, on_complete: Optional[Callable] = None):
        """
        初始化倒计时计时器

        Args:
            minutes: 倒计时分钟数
            on_complete: 倒计时结束时的回调函数
        """
        self.total_seconds = minutes * 60
        self.remaining_seconds = self.total_seconds
        self.on_complete = on_complete
        self.running = False
        self.thread = None
        self.start_time = None
        self.next_run_time = None

    def start(self):
        """启动倒计时"""
        if self.running:
            return

        self.running = True
        self.start_time = datetime.datetime.now()
        self.next_run_time = self.start_time + datetime.timedelta(seconds=self.total_seconds)
        self.remaining_seconds = self.total_seconds

        self.thread = threading.Thread(target=self._countdown)
        self.thread.daemon = True
        self.thread.start()

    def stop(self):
        """停止倒计时"""
        self.running = False
        if self.thread:
            self.thread = None

    def reset(self, minutes: Optional[int] = None):
        """重置倒计时"""
        self.stop()
        if minutes is not None:
            self.total_seconds = minutes * 60
        self.remaining_seconds = self.total_seconds
        self.start()

    def _countdown(self):
        """倒计时线程函数"""
        while self.running and self.remaining_seconds > 0:
            time.sleep(1)
            self.remaining_seconds -= 1

        if self.running and self.on_complete:
            self.on_complete()

    def get_remaining_time(self) -> str:
        """获取剩余时间的格式化字符串"""
        minutes, seconds = divmod(self.remaining_seconds, 60)
        return f"{minutes:02d}:{seconds:02d}"

    def get_next_run_time(self) -> str:
        """获取下次运行时间的格式化字符串"""
        if self.next_run_time:
            return self.next_run_time.strftime("%H:%M:%S")
        return "未设置"

    def get_progress(self) -> float:
        """获取倒计时进度，范围0-1"""
        if self.total_seconds == 0:
            return 0
        return 1 - (self.remaining_seconds / self.total_seconds)


class ProgressBar:
    """进度条，显示排班过程中的进度"""

    def __init__(self, total: int = 100, width: int = 50, prefix: str = "进度", suffix: str = "完成",
                 fill: str = "█", empty: str = "░"):
        """
        初始化进度条

        Args:
            total: 总步骤数
            width: 进度条宽度
            prefix: 进度条前缀
            suffix: 进度条后缀
            fill: 填充字符
            empty: 空白字符
        """
        self.total = total
        self.width = width
        self.prefix = prefix
        self.suffix = suffix
        self.fill = fill
        self.empty = empty
        self.current = 0
        self.start_time = None
        self.last_update_time = None

    def start(self):
        """启动进度条"""
        self.current = 0
        self.start_time = time.time()
        self.last_update_time = self.start_time
        self.update(0)

    def update(self, current: Optional[int] = None, prefix: Optional[str] = None,
               suffix: Optional[str] = None):
        """
        更新进度条

        Args:
            current: 当前步骤
            prefix: 更新的前缀
            suffix: 更新的后缀
        """
        if current is not None:
            self.current = current

        if prefix is not None:
            self.prefix = prefix

        if suffix is not None:
            self.suffix = suffix

        self.last_update_time = time.time()
        self._print_progress()

    def increment(self, steps: int = 1):
        """增加进度"""
        self.current = min(self.current + steps, self.total)
        self.last_update_time = time.time()
        self._print_progress()

    def finish(self):
        """完成进度条"""
        self.current = self.total
        self.last_update_time = time.time()
        self._print_progress()
        print()  # 添加换行

    def _print_progress(self):
        """打印进度条"""
        percent = self.current / self.total
        filled_length = int(self.width * percent)
        bar = self.fill * filled_length + self.empty * (self.width - filled_length)

        # 计算经过的时间
        elapsed_time = time.time() - self.start_time
        elapsed_str = self._format_time(elapsed_time)

        # 计算预计剩余时间
        if percent > 0:
            eta = (elapsed_time / percent) * (1 - percent)
            eta_str = self._format_time(eta)
        else:
            eta_str = "计算中..."

        # 构建进度条字符串
        progress_str = f"\r{self.prefix} |{bar}| {percent:.1%} {self.suffix} [已用时间: {elapsed_str}, 预计剩余: {eta_str}]"

        # 打印进度条
        sys.stdout.write(progress_str)
        sys.stdout.flush()

    def _format_time(self, seconds: float) -> str:
        """格式化时间"""
        m, s = divmod(int(seconds), 60)
        h, m = divmod(m, 60)
        if h > 0:
            return f"{h}时{m}分{s}秒"
        elif m > 0:
            return f"{m}分{s}秒"
        else:
            return f"{s}秒"

    def get_progress(self) -> float:
        """获取进度，范围0-1"""
        return self.current / self.total if self.total > 0 else 0

    def get_elapsed_time(self) -> float:
        """获取已用时间（秒）"""
        if self.start_time is None:
            return 0
        return time.time() - self.start_time

    def get_eta(self) -> float:
        """获取预计剩余时间（秒）"""
        if self.start_time is None or self.current == 0:
            return 0

        elapsed_time = time.time() - self.start_time
        progress = self.current / self.total
        if progress > 0:
            return (elapsed_time / progress) * (1 - progress)
        return 0


class ScheduleMonitor:
    """排班监控器，整合倒计时和进度条功能"""

    def __init__(self, auto_schedule_minutes: int = 1):
        """
        初始化排班监控器

        Args:
            auto_schedule_minutes: 自动排班间隔分钟数
        """
        self.auto_schedule_minutes = auto_schedule_minutes
        self.countdown = CountdownTimer(minutes=auto_schedule_minutes, on_complete=self._on_countdown_complete)
        self.progress_bar = ProgressBar(total=100, prefix="排班进度", suffix="完成")
        self.status = "等待中"
        self.is_scheduling = False
        self.schedule_start_time = None
        self.schedule_end_time = None
        self.schedule_results = {}
        self.display_thread = None
        self.running = False

    def start_monitor(self):
        """启动监控器"""
        if self.running:
            return

        self.running = True
        self.countdown.start()

        self.display_thread = threading.Thread(target=self._display_loop)
        self.display_thread.daemon = True
        self.display_thread.start()

        print(f"排班监控器已启动，自动排班间隔: {self.auto_schedule_minutes}分钟")

    def stop_monitor(self):
        """停止监控器"""
        self.running = False
        self.countdown.stop()
        if self.display_thread:
            self.display_thread = None
        print("\n排班监控器已停止")

    def start_scheduling(self, total_steps: int = 100):
        """
        开始排班进度显示

        Args:
            total_steps: 排班总步骤数
        """
        self.is_scheduling = True
        self.status = "排班中"
        self.schedule_start_time = time.time()
        self.schedule_end_time = None
        self.progress_bar = ProgressBar(total=total_steps, prefix="排班进度", suffix="完成")
        self.progress_bar.start()

    def update_progress(self, current: int, message: Optional[str] = None):
        """
        更新排班进度

        Args:
            current: 当前步骤
            message: 进度消息
        """
        if not self.is_scheduling:
            return

        suffix = f"{message}" if message else "完成"
        self.progress_bar.update(current, suffix=suffix)

    def finish_scheduling(self, results: Optional[Dict[str, Any]] = None):
        """
        完成排班

        Args:
            results: 排班结果
        """
        if not self.is_scheduling:
            return

        self.is_scheduling = False
        self.status = "等待中"
        self.schedule_end_time = time.time()
        self.progress_bar.finish()

        if results:
            self.schedule_results = results
            print(f"排班完成，结果: {results}")
        else:
            print("排班完成")

        # 从全局配置中获取最新的间隔时间
        from config_params import three_shift_params
        current_minutes = three_shift_params.get("auto_schedule_minutes", self.auto_schedule_minutes)

        # 更新实例变量
        self.auto_schedule_minutes = current_minutes

        # 重置倒计时
        self.countdown.reset(self.auto_schedule_minutes)

        print(f"下次排班将在 {self.auto_schedule_minutes} 分钟后进行")

    def _on_countdown_complete(self):
        """倒计时完成回调"""
        print("\n倒计时结束，准备开始排班...")

    def _display_loop(self):
        """显示循环"""
        while self.running:
            if not self.is_scheduling:
                self._display_countdown()
            time.sleep(1)

    def _display_countdown(self):
        """显示倒计时"""
        remaining = self.countdown.get_remaining_time()
        next_run = self.countdown.get_next_run_time()
        progress = int(self.countdown.get_progress() * 50)
        bar = "█" * progress + "░" * (50 - progress)

        sys.stdout.write(f"\r下次排班倒计时: {remaining} |{bar}| 下次运行时间: {next_run} 状态: {self.status}")
        sys.stdout.flush()

    def get_status(self) -> Dict[str, Any]:
        """获取当前状态"""
        return {
            "is_scheduling": self.is_scheduling,
            "status": self.status,
            "countdown_remaining": self.countdown.get_remaining_time(),
            "next_run_time": self.countdown.get_next_run_time(),
            "countdown_progress": self.countdown.get_progress(),
            "schedule_progress": self.progress_bar.get_progress() if self.is_scheduling else 0,
            "schedule_elapsed_time": self.progress_bar.get_elapsed_time() if self.is_scheduling else 0,
            "schedule_eta": self.progress_bar.get_eta() if self.is_scheduling else 0,
            "last_schedule_results": self.schedule_results
        }


# 简单使用示例
if __name__ == "__main__":
    # 创建排班监控器
    monitor = ScheduleMonitor(auto_schedule_minutes=1)

    try:
        # 启动监控器
        monitor.start_monitor()

        # 等待10秒
        time.sleep(10)

        # 模拟排班过程
        print("\n开始排班...")
        monitor.start_scheduling(total_steps=100)

        # 模拟排班进度
        for i in range(1, 101):
            monitor.update_progress(i, f"步骤 {i}/100")
            time.sleep(0.1)

        # 完成排班
        monitor.finish_scheduling({"success": True, "items": 100})

        # 再等待10秒
        time.sleep(10)

    except KeyboardInterrupt:
        print("\n用户中断")
    finally:
        # 停止监控器
        monitor.stop_monitor()
